package redis.client.nedis.cluster;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

/**
 * redis集群节点信息
 *
 * @author gaodong
 */
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class ClusterNode {

    /***
     * id: 节点ID,是一个40字节的随机字符串，这个值在节点启动的时候创建，并且永远不会改变（除非使用CLUSTER RESET HARD命令）。
     * ip:port: 客户端与节点通信使用的地址.
     * flags: 逗号分割的标记位，可能的值有: myself, master, slave, fail?, fail, handshake, noaddr, noflags. 下一部分将详细介绍这些标记.
     * master: 如果节点是slave，并且已知master节点，则这里列出master节点ID,否则的话这里列出”-“。
     * ping-sent: 最近一次发送ping的时间，这个时间是一个unix毫秒时间戳，0代表没有发送过.
     * pong-recv: 最近一次收到pong的时间，使用unix时间戳表示.
     * config-epoch: 节点的epoch值（or of the current master if the node is a slave）。每当节点发生失败切换时，都会创建一个新的，独特的，递增的epoch。如果多个节点竞争同一个哈希槽时，epoch值更高的节点会抢夺到。
     * link-state: node-to-node集群总线使用的链接的状态，我们使用这个链接与集群中其他节点进行通信.值可以是 connected 和 disconnected.
     * slot: 哈希槽值或者一个哈希槽范围. 从第9个参数开始，后面最多可能有16384个 数(limit never reached)。代表当前节点可以提供服务的所有哈希槽值。如果只是一个值,那就是只有一个槽会被使用。如果是一个范围，这个值表示为起始槽-结束槽，节点将处理包括起始槽和结束槽在内的所有哈希槽。
     */
    private String id;
    private String ip;
    private int port;
    private String flags;
    private String master;
    private ClusterNode master_node;
    private long ping_sent;
    private long pong_recv;
    private int config_epoch;
    private String link_state;
    private Slot[] slots;

    /**
     * 解析字符串为ClusterNode
     *
     * @param str 带解析字符串
     * @return
     */
    public static ClusterNode deserialize(String str) {
        ClusterNode node = new ClusterNode();

        String[] arr = str.split(" ");
        node.setId(arr[0]);

        String ipport = arr[1];
        String[] arripport = ipport.split(":");
        String[] arrport = arripport[1].split("@");
        node.setIp(arripport[0]);
        node.setPort(Integer.parseInt(arrport[0]));

        node.setFlags(arr[2]);
        node.setMaster(arr[3]);
        node.setPing_sent(Long.parseLong(arr[4]));
        node.setPong_recv(Long.parseLong(arr[5]));
        node.setConfig_epoch(Integer.parseInt(arr[6]));
        node.setLink_state(arr[7]);

        if (arr.length > 8) {
            Slot[] slots = new Slot[arr.length - 8];
            for (int i = 0; i < slots.length; i++) {
                String[] nums = arr[i + 8].split("-");
                int start = Integer.parseInt(nums[0]);
                int end = Integer.parseInt(nums[nums.length - 1]);
                slots[i] = new Slot(start, end);
            }
            node.setSlots(slots);
        }

        return node;
    }

    @Setter
    @Getter
    @NoArgsConstructor
    @AllArgsConstructor
    static class Slot {
        private int start;
        private int end;
    }
}
